package com.zkrt.upms.service.impl;


import com.alibaba.fastjson.JSONObject;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.influxdb.client.InfluxDBClient;
import com.influxdb.client.QueryApi;
import com.influxdb.query.FluxTable;
import com.zkrt.upms.common.config.InfluxDBConfig;
import com.zkrt.upms.common.util.DateUtils;
import com.zkrt.upms.dto.InfluxDto;
import com.zkrt.upms.dto.InfluxNewDto;
import com.zkrt.upms.entity.AttributeData;
import com.zkrt.upms.service.InfluxdbService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.ZoneId;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service("influxdbService")
@Slf4j
public class InfluxdbServiceImpl implements InfluxdbService {

    @Autowired
    private InfluxDBClient influxDBClient;

    @Autowired
    private InfluxDBConfig influxDBConfig;


    @Override
    public Object query(String flux, String code, Map<String, Object> map) {
        /*if (code.equals("CJ_ELECTRIC_CONSUME")) {
            return cjElectricConsume(flux, map);
        } else if (code.equals("CJ_SENSOR_HISTORY")) {
            return cjSensorHistory(flux, map);
        }*/
        return null;
    }


    @Override
    public Object query(String flux, String code) {
        return null;
    }

    @Override
    public Map<String, List<AttributeData>> getHistories(String bucket, InfluxDto influxDto, Date start, Date end) {

        QueryApi queryApi = influxDBClient.getQueryApi();

        List<String> parametrizedQuery = new ArrayList<>();

        parametrizedQuery.add(String.format("from(bucket: \"%s\")", bucket));
        parametrizedQuery.add(String.format("range(start: %s, stop: %s)", DateUtils.subtract8Hours(start) ,DateUtils.subtract8Hours(end))); // toInfluxDate 就是给小时减了8小时，其实在前端处理更合理，只是我们系统没有国际化的需求，算是给前端偷懒了
        if (StringUtils.isNotEmpty(influxDto.getMeasureName())){
            parametrizedQuery.add(String.format("filter(fn: (r) => r[\"_measurement\"] == \"%s\")", influxDto.getMeasureName()));
        }


        if (StringUtils.isNotEmpty(influxDto.getDevSn())){
            /*String devSnFilter = influxDto.getDevSn().stream().map(devSn -> String.format("r[\"devSn\"] == \"%s\"", devSn)).collect(Collectors.joining(" or "));

            log.info("拿到了:"+devSnFilter);*/
            parametrizedQuery.add(String.format("filter(fn: (r) => r[\"devSn\"] == \"%s\")", influxDto.getDevSn()));
            //parametrizedQuery.add(String.format("devSn(fn: (r) => %s)", devSnFilter));
        }

        if (influxDto.getFields()!=null&&influxDto.getFields().size()>0){
            String filedFilter = influxDto.getFields().stream().map(field -> String.format("r[\"_field\"] == \"%s\"", field)).collect(Collectors.joining(" or "));
            parametrizedQuery.add(String.format("filter(fn: (r) => %s)", filedFilter));
        }

        /**
         * 查询整点数据
         */
        parametrizedQuery.add("window(every: 1h, createEmpty: false)");
        parametrizedQuery.add("first()");
        parametrizedQuery.add("window(every: inf)");

        /**
         * 排序 按时间倒序
         */
        parametrizedQuery.add("sort(columns: [\"_time\"], desc: true)");

        /**
         * 分页
         */
        //parametrizedQuery.add(String.format("limit(n: %s, offset: %s)", pageSize, pageSize * (pageNum - 1)));

        Map<String, List<AttributeData>> result = new HashMap<>();

        List<FluxTable> tables = queryApi.query(String.join(" |> ", parametrizedQuery));

        for (FluxTable table : tables) {

            List<List> list = table.getRecords().stream().map(record ->
                    Arrays.asList(record.getValue(), record.getTime().atZone(ZoneId.systemDefault()).toLocalDateTime())  // 日期直接转成本地的，前端拿去直接用
            ).collect(Collectors.toList());

            ArrayList<AttributeData> dataList = new ArrayList<>();
            list.forEach(s->{
                AttributeData data = new AttributeData();
                data.setValue(s.get(0).toString());
                data.setTheTime(s.get(1).toString());
                dataList.add(data);
            });


            result.put(table.getRecords().get(0).getField(), dataList);
        }

        return result;

    }

    @Override
    public AttributeData getNew(String bucket, InfluxNewDto influxNewDto){
        QueryApi queryApi = influxDBClient.getQueryApi();

        List<String> parametrizedQuery = new ArrayList<>();


        parametrizedQuery.add(String.format("from(bucket: \"%s\")", bucket));

        Date end = new Date();

        Calendar calendar = Calendar.getInstance();
        calendar.setTime(end);
        calendar.add(Calendar.HOUR_OF_DAY, -24);
        Date start = calendar.getTime();

        parametrizedQuery.add(String.format("range(start: %s, stop: %s)",DateUtils.subtract8Hours(start) ,DateUtils.subtract8Hours(end)));

        if (StringUtils.isNotEmpty(influxNewDto.getMeasureName())) {
            parametrizedQuery.add(String.format("filter(fn: (r) => r[\"_measurement\"] == \"%s\")", influxNewDto.getMeasureName()));

        }

        if (StringUtils.isNotEmpty(influxNewDto.getDevSn())){
            parametrizedQuery.add(String.format("filter(fn: (r) => r[\"devSn\"] == \"%s\")", influxNewDto.getDevSn()));

        }

        if (StringUtils.isNotEmpty(influxNewDto.getField())){
            parametrizedQuery.add(String.format("filter(fn: (r) => r[\"_field\"] == \"%s\")", influxNewDto.getField()));

        }

        parametrizedQuery.add("sort(columns: [\"_time\"], desc: true)");

        parametrizedQuery.add(String.format("limit(n: 1, offset: 0)"));

        Map<String, List<List>> result = new HashMap<>();

        List<FluxTable> tables = queryApi.query(String.join(" |> ", parametrizedQuery));

        for (FluxTable table : tables) {

            List<List> list = table.getRecords().stream().map(record ->
                    Arrays.asList(record.getValue(), record.getTime().atZone(ZoneId.systemDefault()).toLocalDateTime())  // 日期直接转成本地的，前端拿去直接用
            ).collect(Collectors.toList());

            result.put(table.getRecords().get(0).getField(), list);
        }

        AttributeData attributeData = new AttributeData();
        if (result!=null&&result.size()>0){
            List list = result.get(influxNewDto.getField()).get(0);

            attributeData.setValue(list.get(0).toString());
            attributeData.setTheTime(DateUtils.getDateByInflux(list.get(1).toString()));
            return  attributeData;
        }
        return attributeData;
    }

    private static Map<String, Object> extracted(JSONObject items) {
        return items.keySet().stream()
                .collect(Collectors.toMap(Function.identity(), key -> {
                    JSONObject boj = items.getJSONObject(key);
                    return boj.get("value");
                }));
    }
}
